package org.fixies.resource;

import org.fixies.utils.Validator;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;


/**
 * ファイルシステムからリソースをロードするリソースローダー
 *
 * @author Kawasaki
 */
public abstract class FileSystemResourceLoader implements ResourceLoader {

    /**
     * ファイルセパレータ
     */
    protected static final String FILE_SEPARATOR = System
            .getProperty("file.separator");

    private final List<String> resouceRootDirs_;


    public FileSystemResourceLoader(String... resourceRootDirs) {
        Validator.notNullOrEmpty(resourceRootDirs);
        resouceRootDirs_ = appendFileSeparator(resourceRootDirs);
    }

    private List<String> appendFileSeparator(String[] orig) {
        List<String> result = new ArrayList<String>(orig.length);
        for (String e : orig) {
            e = e.endsWith(FILE_SEPARATOR) ? e : e + FILE_SEPARATOR;
            result.add(e);
        }
        return result;
    }

    /**
     * @see org.fixies.resource.ResourceLoader#loadResource(java.lang.String, java.lang.Class)
     */
    public InputStream loadResource(String resourceName, Class<?> clazz) {
        String path = getPackagePath(clazz) + FILE_SEPARATOR + resourceName;
        return loadResource(path);
    }

    /*
      * @see org.fixies.resource.ResourceLoader#loadResource(java.lang.String)
      */

    public InputStream loadResource(String resourceName) {

        List<String> rootDirs = getResourceRootDirs();
        List<String> resourcePaths = new ArrayList<String>(rootDirs.size());

        // ルートディレクトリ群からリソースの読込を試行する。
        for (String rootDir : rootDirs) {
            String resourcePath = rootDir + resourceName;
            resourcePaths.add(resourcePath);
            try {
                // 最初に発見したリソースを返却する
                return new FileInputStream(resourcePath);
            } catch (FileNotFoundException ignore) {
                // NOP
            }
        }
        // 全てのディレクトリ群から読込失敗
        StringBuilder msg = new StringBuilder().append("File not found. ");
        for (String resourcePath : resourcePaths) {
            msg.append("resource path=[").append(resourcePath).append("] ");
        }
        throw new ResourceNotFoundException(msg.toString());
    }

    /**
     * パッケージをパスとして取得する。川崎健
     * 与えられたクラスのパッケージを抽出する。
     * jp.co.tis.Sampleクラスの場合、jp/co/tisが返却される。
     *
     * @param clazz クラス
     * @return
     */
    private String getPackagePath(Class<?> clazz) {
        return clazz.getPackage().getName().replace(".", FILE_SEPARATOR);
    }

    protected List<String> getResourceRootDirs() {
        return resouceRootDirs_;
    }
}
